
package cn.jbolt.ai.app.service.impl;

import cn.hutool.core.util.StrUtil;
import cn.jbolt.ai.app.AppType;
import cn.jbolt.ai.app.dao.AiAppMapper;
import cn.jbolt.ai.app.entity.*;
import cn.jbolt.ai.app.service.*;
import cn.jbolt.ai.app.vo.*;
import cn.jbolt.ai.core.chain.node.action.funccall.FuncCallNodeConfig;
import cn.jbolt.ai.core.chain.node.action.klb.KlbChatNodeConfig;
import cn.jbolt.ai.core.chain.node.action.klb.KlbSearchNodeConfig;
import cn.jbolt.ai.core.chain.node.base.AppConfigConstant;
import cn.jbolt.ai.core.chain.node.base.LlmConfig;
import cn.jbolt.ai.core.chain.node.base.UiAppConfig;
import cn.jbolt.ai.klb.service.AiKnowledgeBaseService;
import cn.jbolt.ai.resource.function.entity.AiFunctionResource;
import cn.jbolt.util.cache.CacheUtil;
import cn.jbolt.util.JSONUtil;
import cn.jbolt.util.Pager;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import cn.jbolt.ai.klb.entity.AiKnowledgeBase;
import cn.jbolt.ai.resource.function.service.AiFunctionResourceService;
import cn.jbolt.util.Result;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.jboltai.capability.message.AIMessage;
import com.jboltai.capability.message.AIMessageRole;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Objects;


@Service
public class AiAppServiceImpl extends ServiceImpl<AiAppMapper, AiApp> implements AiAppService {

    private static final Logger logger = LoggerFactory.getLogger(AiAppServiceImpl.class);

    @Autowired
    private AiAppConfigService configService;

    @Autowired
    private AiFunctionResourceService aiFunctionResourceService;
    @Autowired
    private AiKnowledgeBaseService knowledgeBaseService;

    @Autowired
    private AiAppSessionService appSessionService;
    @Autowired
    private AiAppMessageService appMessageService;
    @Autowired
    private AiAppNodeService appNodeService;
    @Autowired
    private AiAppDesignService appDesignService;


    @Override
    public Result<AiApp> getAppById(Long id) {
        AiApp cache = getCache(id);
        JsonNode config = configService.getConfig(AppConfigConstant.LINK_TYPE_APP, id);

        if (cache != null) {
            cache.setConfig(config);
            return Result.success(cache);
        }

        AiApp app = this.getById(id);
        if (app != null) {
            app.setConfig(config);
            setCache(app, id);
            setCache(app, app.getSn());
            return Result.success(app);
        } else {
            return Result.error("应用不存在");
        }

    }
    @Override
    public Result<AiApp> getAppBySn(String sn) {
        AiApp app = getCache(sn);
        if (app == null) {
            app = this.getOne(new QueryWrapper<AiApp>().eq("sn", sn));
            if (app == null) {
                return Result.error("应用不存在");
            }
        }

        JsonNode config = configService.getConfig(AppConfigConstant.LINK_TYPE_APP, app.getId());
        app.setConfig(config);
        AccessWebConfig accessWebConfig = configService.getAccessWebConfig(app);
        if (accessWebConfig!=null|| Objects.equals(accessWebConfig.getEnable(), true)){
            app.setAccessWebConfig(accessWebConfig);
        }
        setCache(app, app.getSn());
        setCache(app, app.getId());
        return Result.success(app);


    }

    @Override
    public Result getOnlyAppById(Long id) {
        AiApp cache = getCache(id);
        if (cache != null) {
            return Result.success(cache);
        }
        AiApp app = this.getById(id);
        if (app != null) {
            return Result.success(app);
        } else {
            return Result.error("应用不存在");
        }
    }

    @Override
    public Result<Pager> listByPage(Integer pageNumber, Integer pageSize, Boolean enable, String keywords) {
        QueryWrapper<AiApp> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("is_build_in", false);
        if (enable != null)
            queryWrapper.eq("enable", enable);
        if (StrUtil.isNotBlank(keywords))
            queryWrapper.and(wrapper -> wrapper.like("name", keywords).or().like("sn", keywords));
        queryWrapper.orderByDesc("id");
        Page<AiApp> pager = new Page(pageNumber, pageSize);
        return Result.success(Pager.from(this.page(pager, queryWrapper)));
    }

    @Override
    @Transactional
    public Result add(AiApp app) {
        //编码不可重复
        Result result = checkSnExist(app.getSn(), null);
        if (result.isError()) return result;
        app.setEnable(false);
        app.setBuildIn(false);
        boolean save = this.save(app);
        if (save) {
            if (app.getAppType().equals(AppType.DESIGN.getCode())) { //编排应用
                //创建ai应用的设计表
                AiAppDesign appDesign = new AiAppDesign();
                appDesign.setAppId(app.getId());
                appDesignService.add(appDesign);
                //去创建appConfig
                result = initDesignAppConfig(app);
                if (result.isError()) return result;

            } else { //简单应用
                //去创建appConfig
                result = initSimpleAppConfig(app);
                if (result.isError()) {
                    return result;
                }
                //5个node节点以及他的相关配置
                result = appNodeService.initAppNodes(app.getId());
                if (result.isError()) return result;
            }

            setCache(app, app.getId());
            return Result.success(app);
        } else {
            return Result.error("添加失败");
        }
    }

    private Result initDesignAppConfig(AiApp app) {
        ObjectNode configs = JSONUtil.createObjectNode();
        // uiConfig
        configs.put(AppConfigConstant.CONFIG_TYPE_UI, UiAppConfig.getDefaultConfig());
        //web访问方式,默认是公开访问
        AccessWebConfig accessWebConfig = new AccessWebConfig();
        accessWebConfig.setEnable(true);
        accessWebConfig.setAccessPwd("");
        accessWebConfig.setAccessType(AccessConfigConstant.ACCESS_TYPE_WEB_PUBLIC);
        AccessConfig accessConfig = new AccessConfig();
        accessConfig.setWeb(accessWebConfig);
        configs.put(AccessConfigConstant.ACCESS, JSONUtil.toJsonObject(accessConfig));
        return configService.add(AppConfigConstant.LINK_TYPE_APP, app.getId(), configs);
    }

    private Result initSimpleAppConfig(AiApp app) {
        ObjectNode configs = JSONUtil.createObjectNode();
        // uiConfig
        configs.put(AppConfigConstant.CONFIG_TYPE_UI, UiAppConfig.getDefaultConfig());
        //web访问方式,默认是公开访问
        AccessWebConfig accessWebConfig = new AccessWebConfig();
        accessWebConfig.setEnable(true);
        accessWebConfig.setAccessPwd("");
        accessWebConfig.setAccessType(AccessConfigConstant.ACCESS_TYPE_WEB_PUBLIC);
        AccessConfig accessConfig = new AccessConfig();
        accessConfig.setWeb(accessWebConfig);
        configs.put(AccessConfigConstant.ACCESS, JSONUtil.toJsonObject(accessConfig));
        //funcCallNodeConfig
        configs.put(AppConfigConstant.CONFIG_TYPE_FUNCCALL, FuncCallNodeConfig.getDefaultConfig());
        // KlbSearchNodeConfig
        KlbSearchNodeConfig klbSearchNodeConfig = new KlbSearchNodeConfig();
        klbSearchNodeConfig.setOutputField("klb_search_result");
        klbSearchNodeConfig.setInputField(AppConfigConstant.ATTR_KEY_PROMPT);
        configs.put(AppConfigConstant.CONFIG_TYPE_KLB_SEARCH, JSONUtil.toJsonObject(klbSearchNodeConfig));
        // llmConfig
        LlmConfig llm = new LlmConfig();
        llm.setInputField(AppConfigConstant.ATTR_KEY_PROMPT);
        llm.setStream(true);
        llm.setUseContext(true);
        llm.setOutputToResponse(true);
        llm.setOutputThinking(false);//是否展示思考过程,默认变成false
        llm.setPersistDb(true);
        configs.put(AppConfigConstant.CONFIG_TYPE_LLM, JSONUtil.toJsonObject(llm));
        //KlbChatNodeConfig
        KlbChatNodeConfig klbChatNodeConfig = new KlbChatNodeConfig();
        klbChatNodeConfig.setShowWithHtml(false);
        klbChatNodeConfig.setKlbResultField("klb_search_result");
        klbChatNodeConfig.setNoMatchReply("抱歉您的问题无法回答");
        klbChatNodeConfig.setOnlyKlb(false);
        configs.put(AppConfigConstant.CONFIG_TYPE_KLB_CHAT,JSONUtil.toJsonObject(klbChatNodeConfig));
        return configService.add(AppConfigConstant.LINK_TYPE_APP, app.getId(), configs);
    }

    /**
     * 查询编码
     *
     * @param sn
     * @return
     */
    public Result checkSnExist(String sn, Long exceptId) {
        QueryWrapper<AiApp> query = new QueryWrapper<AiApp>().eq("sn", sn);
        if (exceptId != null) {
            query.ne("id", exceptId);
        }
        if (this.count(query) > 0) {
            return Result.error("编码不可重复");
        } else {
            return Result.success();
        }
    }

    @Override
    public Result update(AiApp app) {
        AiApp db = getById(app.getId());
        if (checkSnExist(app.getSn(), app.getId()).isError()) {
            return Result.error("编码已存在");
        }
        boolean updated = updateById(app);
        if (updated) {
            setCache(app, app.getId());
            CacheUtil.removeObject(CacheUtil.KEY_APP + "_sn_" + db.getSn());
            setCache(app, app.getSn());
            return Result.success();
        } else {
            return Result.error("更新失败");
        }
    }

    @Override
    @Transactional
    public Result del(Long id) {
        AiApp app = this.getById(id);
        if (app != null) {
            if (app.getEnable()) {
                return Result.error("应用正在使用中，不能删除");
            }
        } else {
            return Result.error("应用不存在");
        }
        //只有关闭的状态才能删除
        boolean deleted = removeById(id);
        if (deleted) {
            try {
                CacheUtil.removeObject(CacheUtil.KEY_APP + "_" + id);
                CacheUtil.removeObject(CacheUtil.KEY_APP + "_sn_" + app.getSn());
                logger.info("缓存中app移除成功:{}_{}", CacheUtil.KEY_APP, id);
                //app移除相关的节点,节点移除相关的配置
                Result nodeResult = appNodeService.delAllNodeByAppId(id);
                if (nodeResult.isError()) return nodeResult;
                //app移除app的相关配置
                List<Long> idList = new ArrayList<>();
                idList.add(id);
                Result configResult = configService.deleteByLinkType(AppConfigConstant.LINK_TYPE_APP, idList);
                if (configResult.isError()) return configResult;
                //appSession移除
                Result sessionResult = appSessionService.deleteByAppId(id);
                if (sessionResult.isError()) return sessionResult;
                //appMessage移除
                Result msgResult = appMessageService.deleteMsgByAppId(id);
                if (msgResult.isError()) return msgResult;
            } catch (Exception e) {
                e.printStackTrace();
                logger.error("删除失败");
                return Result.error(e.getMessage());
            }
        } else {
            return Result.error("删除失败");
        }
        return Result.success();
    }

    @Override
    public Result toggleEnable(Long id) {
        Result result = getAppById(id);
        if (result.isError()) {
            return result;
        }
        AiApp app = (AiApp) result.getData();
        Boolean enable = !app.getEnable();
        app.setEnable(enable);
        boolean updated = updateById(app);
        if (updated) {
            setCache(app, app.getId());
            setCache(app, app.getSn());
            return Result.success();
        } else {
            return Result.error("更新启用状态失败");
        }
    }

//    @Override
//    public Result updateAppLinkCount(Long appId, String type, Integer size) {
//        UpdateWrapper<AiApp> updateWrapper = new UpdateWrapper<>();
//        if (type.equals( AppConfigConstant.CONFIG_TYPE_KLB)) {
//            updateWrapper.eq("id", appId).set("knowledge_base_count", size);
//
//        } else if (type.equals( AppConfigConstant.CONFIG_TYPE_FUNCCALL)) {
//            updateWrapper.eq("id", appId).set("function_count", size);
//        }
//        boolean update = this.update(updateWrapper);
//        if (update) {
//            //移除缓存
//            CacheUtil.removeObject(CacheUtil.KEY_APP + "_" + appId);
//            logger.info("缓存中app移除成功:{}_{}", CacheUtil.KEY_APP, appId);
//            //添加缓存
//            setCache(getById(appId), appId);
//            return Result.success();
//        } else {
//            return Result.error("更新失败");
//        }
//    }

    /**
     * 开启上下文,获取前20条消息
     *
     * @return
     */
    public List<AIMessage> getSessionContextMessages(Long sessionId, Long startId, Integer limit) {
        Result result = appMessageService.getSessionContextMsg(sessionId, startId, limit);
        List<AiAppMessage> messageList = (List<AiAppMessage>) result.getData();
        List<AIMessage> list = new ArrayList<>();
        for (AiAppMessage dbMessage : messageList) {
            AIMessage aiMessage = new AIMessage();
            aiMessage.setId(dbMessage.getId().toString());
            if (dbMessage.getRole().equals(AIMessageRole.assistant.name())) {
                aiMessage.setRole(AIMessageRole.assistant);
            } else if (dbMessage.getRole().equals(AIMessageRole.user.name())) {
                aiMessage.setRole(AIMessageRole.user);
            }
            StringBuilder content = new StringBuilder();
            if (StrUtil.isNotBlank(dbMessage.getContent())) {
                if (JSONUtil.isTypeJSONArray(dbMessage.getContent())) {
                    ArrayNode msgs = JSONUtil.toJsonArray(dbMessage.getContent());
                    if (msgs.isEmpty() == false && msgs.get(0).has("renderType")) {
                        msgs.elements().forEachRemaining(jsonNode -> {
                            content.append(jsonNode.get("content").asText()).append("\n");
                        });
                    }
                }
            }
            aiMessage.setContent(content.length() > 0 ? content.toString() : dbMessage.getContent());
            list.add(aiMessage);
        }
        return list;

    }

    @Override
    @Transactional
    public Result submitKnowledgeBases(AiAppLinkSubmitVO vo) {
        Long appId = vo.getAppId();
        //先判断app应用是否存在
        Result result = this.getAppById(appId);
        if (result.isError()) {
            return result;
        }
        if (vo.getList() == null || vo.getList().size() == 0) {
            return Result.error("请绑定知识库");
        }
        if (vo.getList().size() > 1) {
            return Result.error("只可绑定一个知识库");
        }

//        //更新app中的知识库的数量
//        Result updateResult = this.updateAppLinkCount(appId,  AppConfigConstant.CONFIG_TYPE_KLB, vo.getList().size());
//        if (updateResult.isError()) {
//            return Result.error("绑定失败");
//        }

        //去配置表中查询
        JsonNode jsonNode = configService.getObjectConfigByCondition(AppConfigConstant.LINK_TYPE_APP, appId, AppConfigConstant.CONFIG_TYPE_KLB_SEARCH);
        if (jsonNode == null) {
            jsonNode = JSONUtil.createObjectNode();
        }

        KlbSearchNodeConfig klbSearchNodeConfig = JSONUtil.toObject(jsonNode, KlbSearchNodeConfig.class);
        klbSearchNodeConfig.setKlbId(vo.getList().get(0));
        Result klbResult = configService.updateConfigByKey(AppConfigConstant.LINK_TYPE_APP, appId,
                AppConfigConstant.CONFIG_TYPE_KLB_SEARCH, JSONUtil.toJson(klbSearchNodeConfig));
        return klbResult;
    }

    /**
     * 移除挂载的知识库
     *
     * @param vo
     * @return
     */
    @Override
    public Result removeKnowledgeBases(AiAppLinkSubmitVO vo) {
        Long appId = vo.getAppId();
        //先判断app应用是否存在
        Result result = this.getAppById(appId);
        if (result.isError()) {
            return result;
        }
        if (vo.getList() == null || vo.getList().size() == 0) {
            return Result.error("请选择移除的知识库");
        }

        //去配置表中查询
        JsonNode jsonNode = configService.getObjectConfigByCondition(AppConfigConstant.LINK_TYPE_APP, appId, AppConfigConstant.CONFIG_TYPE_KLB_SEARCH);
        if (jsonNode == null) {
            jsonNode = JSONUtil.createObjectNode();
        }

        KlbSearchNodeConfig klbSearchNodeConfig = JSONUtil.toObject(jsonNode, KlbSearchNodeConfig.class);
        klbSearchNodeConfig.setKlbId(null);
        Result klbResult = configService.updateConfigByKey(AppConfigConstant.LINK_TYPE_APP, appId,
                AppConfigConstant.CONFIG_TYPE_KLB_SEARCH, JSONUtil.toJson(klbSearchNodeConfig));
        return klbResult;
    }

    @Override
    @Transactional
    public Result submitFunction(AiAppLinkSubmitVO vo) {
        Long appId = vo.getAppId();
        //先判断app应用是否存在
        Result result = this.getAppById(appId);
        if (result.isError()) {
            return result;
        }
//        if (vo.getList() == null || vo.getList().size() == 0) {
//            return Result.error("请绑定functionCall");
//        }

//    / /        //更新app中的functionCall的数量
//    / /        Result updateResult = this.updateAppLinkCount(appId, AppConfigConstant.CONFIG_TYPE_FUNCCALL, vo.getList().size());
//    / /        if (updateResult.isError()) {
//    / /            return Result.error("绑定失败");
//    / /        }
        //去配置表中查询
        JsonNode jsonNode = configService.getObjectConfigByCondition(AppConfigConstant.LINK_TYPE_APP, appId, AppConfigConstant.CONFIG_TYPE_FUNCCALL);
        if (jsonNode == null) {
            jsonNode = JSONUtil.createObjectNode();
        }
        FuncCallNodeConfig nodeConfig = JSONUtil.toObject(jsonNode, FuncCallNodeConfig.class);
        //把long的list换成String的数组
        String[] stringArray = vo.getList().stream()
                .map(String::valueOf)
                .toArray(String[]::new);
        nodeConfig.setFunctions(stringArray);
        Result configResult = configService.updateConfigByKey(AppConfigConstant.LINK_TYPE_APP, appId, AppConfigConstant.CONFIG_TYPE_FUNCCALL, JSONUtil.toJson(nodeConfig));
        return configResult;


    }

    @Override
    public Result getKlbByAppId(Long appId) {
        //去配置表中查询
        JsonNode klbConfig = configService.getObjectConfigByCondition(AppConfigConstant.LINK_TYPE_APP, appId, AppConfigConstant.CONFIG_TYPE_KLB_SEARCH);
        if (klbConfig == null) {
            return Result.success(null);
        }
        KlbSearchNodeConfig nodeConfig = JSONUtil.toObject(klbConfig, KlbSearchNodeConfig.class);
        Long klbId = nodeConfig.getKlbId();
        if (klbId == null) {
            return Result.success(null);
        }
        AiKnowledgeBase knowledgeBase = knowledgeBaseService.getById(klbId);
        if (knowledgeBase == null) {
            return Result.success(null);
        }
        AiAppToolVO klb = new AiAppToolVO();
        klb.setKey(klbId.toString());
        klb.setCreateTime(knowledgeBase.getCreateTime());
        klb.setEnable(knowledgeBase.getEnable());
        klb.setValue(knowledgeBase.getName());
        klb.setBriefInfo(knowledgeBase.getBriefInfo());
        List<AiAppToolVO> VOlist = new ArrayList<>();
        VOlist.add(klb);
        return Result.success(VOlist);
    }

    @Override
    public Result getFuncByAppId(Long appId) {

        //去配置表中查询
        JsonNode funcConfig = configService.getObjectConfigByCondition(AppConfigConstant.LINK_TYPE_APP, appId, AppConfigConstant.CONFIG_TYPE_FUNCCALL);
        if (funcConfig == null) {
            return Result.success(null);
        }
        FuncCallNodeConfig nodeConfig = JSONUtil.toObject(funcConfig, FuncCallNodeConfig.class);
        String[] functions = nodeConfig.getFunctions();

        if (functions == null || functions.length == 0) {
            return Result.success(null);
        }
        List<AiFunctionResource> functionResourceList = aiFunctionResourceService.getFunctionResourceList(functions);
        if (functionResourceList == null && functionResourceList.size() == 0) {
            return Result.success(null);
        }
        List<AiAppToolVO> kvList = new ArrayList<>();
        for (AiFunctionResource resource : functionResourceList) {
            AiAppToolVO vo = new AiAppToolVO();
            vo.setKey(resource.getId().toString());
            vo.setSn(resource.getSn());
            vo.setBriefInfo(resource.getBriefInfo());
            vo.setServiceClass(resource.getServiceClass());
            vo.setValue(resource.getSn() + resource.getBriefInfo());
            kvList.add(vo);
        }
        return Result.success(kvList);

    }


    @Override
    public Result getAppType() {
        return Result.success(AppType.toList());
    }
    @Override
    public Result checkAccessPwd(AccessCheckData data) {
        Result<AiApp> res = getAppById(data.getAppId());
        if (res.isError()) {
            return res;
        }
        AiApp app = res.getData();
        //去配置中查询找到accessConfig对象
        JsonNode accessConfig = configService.getObjectConfigByCondition(AppConfigConstant.LINK_TYPE_APP, app.getId(),
                AccessConfigConstant.ACCESS);
        if (accessConfig == null) {
            return Result.error("该应用没有配置网页访问方式");
        }
        JsonNode webJsonNode = accessConfig.get(AccessConfigConstant.CONFIG_TYPE_WEB);
        AccessWebConfig webConfig = JSONUtil.toObject(webJsonNode, AccessWebConfig.class);
        return Result.success(Objects.equals(webConfig.getAccessPwd(), data.getPwd()));
    }
    /**
     * 从缓存中获取app
     *
     * @return
     */
    public AiApp getCache(Long appId) {
        AiApp cacheApp = CacheUtil.getObject(CacheUtil.KEY_APP + "_" + appId);
        logger.info("缓存中取出app:{}_{}-----{}:", CacheUtil.KEY_APP, appId, cacheApp);
        return cacheApp;
    }
    /**
     * 从缓存中获取app
     *
     * @return
     */
    public AiApp getCache(String sn) {
        AiApp cacheApp = CacheUtil.getObject(CacheUtil.KEY_APP + "_sn_" + sn);
        logger.info("sn缓存中取出app:{}_{}-----{}:", CacheUtil.KEY_APP, sn, cacheApp);
        return cacheApp;
    }

    /**
     * 把app放入缓存
     *
     * @param app
     */
    public void setCache(AiApp app, Long appId) {
        CacheUtil.putObject(CacheUtil.KEY_APP + "_" + appId, app, -1, null);
        logger.info("app存入缓存:{}_{},已放入缓存,无过期时间-----{}:", CacheUtil.KEY_APP, appId, app);
    }
    /**
     * 把app放入缓存
     *
     * @param app
     */
    public void setCache(AiApp app, String sn) {
        CacheUtil.putObject(CacheUtil.KEY_APP + "_sn_" + sn, app, -1, null);
        logger.info("app存入缓存:{}_{},已放入缓存,无过期时间-----{}:", CacheUtil.KEY_APP, sn, app);
    }
}
